<?


class Filter 
/*
Filter - библиотека функций для проверки и приведению к безопасному виду входных данных 

(класс требует доработки)

Методы:
	Filter::values($values, $options);
	Filter::filename($str)
	Filter::translit($str)
	Filter::dirname($str)
	Filter::filpath($str)
	Filter::date($str)
	Filter::email($str)
	Filter::password($str)
	Filter::url($str)
	Filter::xss($str)
	Filter::html($str)
	Filter::sql($str)
	Filter::intval($str)
	Filter::floatval($str)
	Filter::chars($str)
	Filter::strings($str)
	Filter::varname($str) - имя переменной A-Za-z_
	Filter::varname_php($str) - имя переменной PHP
	Filter::varname_js($str) - имя переменной JS
	
*/
{
	
	// создает корректное имя файла из предложеной строки: траситерация + замена опасных символов на подчерки
	static function filename($str)
	{
		$str = self::translit($str);
		$str = preg_replace(
			array(
				'/[^0-9a-z\`\~\!\@\#\$\%\^\(\)\; \,\.\'\/\_\-]/i',
				'/\s+/', '/_-/', '/_+/'
				),
			'_', 
			$str
			);
		
		return $str;
		
	}
		static function valid_filename($str) 
		{
			return preg_replace('/[^0-9a-zа-яіїё\`\~\!\@\#\$\%\^\*\(\)\; \,\.\'\/\_\-]/i', ' ',$str); 
		}
		/*  remove repeated ../
		while( preg_match( [expression], $input ) )
		{
		   $input = preg_replace( [expression], "", $input );
		}

		*/

		static function CleanFileName( $Raw ){ 
			$Raw = trim($Raw); 
			$RemoveChars  = array( "([\40])" , "([^a-zA-Z0-9-])", "(-{2,})" ); 
			$ReplaceWith = array("-", "", "-"); 
			return preg_replace($RemoveChars, $ReplaceWith, $Raw); 
		} 
		
		
		static function string_to_filename($word) {
			$tmp = preg_replace('/^\W+|\W+$/', '', $word); // remove all non-alphanumeric chars at begin & end of string
			$tmp = preg_replace('/\s+/', '_', $tmp); // compress internal whitespace and replace with _
			return strtolower(preg_replace('/\W-/', '', $tmp)); // remove all non-alphanumeric chars except _ and -
		}
		
		static function clean_filename($filename){//function to clean a filename string so it is a valid filename 
  $reserved = preg_quote('\/:*?"<>|', '/');//characters that are  illegal on any of the 3 major OS's 
  //replaces all characters up through space and all past ~ along with the above reserved characters 
  return preg_replace("/([\\x00-\\x20\\x7f-\\xff{$reserved}])/e", "_", $filename); 
} 

	

		
	// htmlurl2link	
	static function clickable($url){
		$url                                    =    str_replace("\\r","\r",$url);
		$url                                    =    str_replace("\\n","\n<BR>",$url);
		$url                                    =    str_replace("\\n\\r","\n\r",$url);

		$in=array(
		'`((?:https?|ftp)://\S+[[:alnum:]]/?)`si',
		'`((?<!//)(www\.\S+[[:alnum:]]/?))`si'
		);
		$out=array(
		'<a href="$1"  rel=nofollow>$1</a> ',
		'<a href="http://$1" rel=\'nofollow\'>$1</a>'
		);
		return preg_replace($in,$out,$url);
    }
	// Cuts off long URLs at $url_length, and appends "..."
    static function reduceurl($url, $url_length) {
        $reduced_url = substr($url, 0, $url_length);
        if (strlen($url) > $url_length) $reduced_url .= '...';
        
        return $reduced_url;
    }

    // Makes URLs with brackets into links
    // The regex searches for "http://" or equivalent, then various character possibilities (I don't know if it might be possible to exploit this if more characters were allowed). The "e" after the regex allows the reduceurl() to be evaluated.

    static function url2link($linktext) {
        $linktext = preg_replace("#\[(([a-zA-Z]+://)([a-zA-Z0-9?&%.;:/=+_-]*))\]#e", "'<a href=\"$1\" target=\"_blank\">' . reduceurl(\"$3\", 30) . '</a>'", $linktext);
                
        return $linktext;
    } 
	
	
	
	/***
		Filter:: extract_tags ($html, $tag, $use_placeholder=false, $return_innerHTML=false) - извлекает из HTML-кода контейнеры заданного тега, возвращает массив с извлеченными тегами или их содержимым. 
		
		Параметры:
		
		$html	- исходный HTML код, если аргумент $html передан по ссылке - то исходная переменная изменяется - извлекаемые контейнеры тегов заменются на пустые строки или плейсхолдеры (при $use_placeholder=true). 
		
		$tag	- HTML тег, который нужно извлечь, например  'script'
		
		$use_placeholder - нужно ли в переменной $html подставлять уникальные плейсхолдеры вместо контейнеров тегов?  
		
		Если $use_placeholder = FALSE (по умолчанию), то контейнеры тегов замещаются пустой строкой.  Возвращается обычный массив с цифровыми индексами, у которого значения - это извлеченные контейнеры тегов.	 
		Если $use_placeholder = TRUE, то контейнеры тегов замещаются уникальными плейсхолдерами. Возвращается ассоциативный массив, у которого ключи - это строки плейсхолдеров, а значения - это контейнеры тегов.	 Это может быть полезно, если нужно обработать контейнеры тегов и/или позже вернуть их на прежнее место. 
		
		$return_innerHTML  - если установлено, то возвращается внутреннее содержимое тегов. По умолчанию возвращаются полные контейнеры тегов (вместе с открывающим и закрывающим тегом).  
				
	*/
	static function extract_tags( $tag, &$html, $use_placeholder=false, $return_innerHTML=false)
	{
		// приводим описание тега к стандартному виду 'tagname'
		$tag = trim($tag,' <>');
		
		// счетчик вызовов используется в создании плейсхолдера
		static $call_counter=0;
		$call_counter++;
		
		// шаблон для уникального плейсхолдера (содержит номер вызова функции и номера тега, подставляется вместо контейнеров тега) 
		$placeholder_tpl = '[extract_tags_%call%_placeholder_%i%]';
		$placeholder = '';			 
			
		// извлекгем контенеры заданного тега в массив
		preg_match_all(
			"`<{$tag}[^>]*>(.*)</{$tag}>`isU",
			$html,$mathes, 
			PREG_OFFSET_CAPTURE  // это на тот случай, если в будущем понадобятся смещения совпавших кодов, чтобы одинаковые коды на разных местах имели разные плейсхолдеры. На данный момент у одинаковых кодов будет одинаковый плейсхолдер
			);	
		if (empty($matches)) return array();
		
		$count = count($mathes);
		$match = $return_innerHTML ? $mathes[1] : $mathes[0];
		
		// фромируем массив с результатами
		$results=array(); 
		for($i=0; $i<$count; $i++)
		{
			// извлекаем совпавший код
			$code = $match[$i][0];
						
			if ($use_placeholder) // использовать плейсхолдеры?
			{
				// генерируем текущий плейсхолдер
				$placeholder = str_replace(
							array('%call%',			'%i%'	),
							array($call_counter, 	$i		),
							
							$placeholder_tpl
							);
				// сохраняем код в ассоциативный массив 
				$results[$placeholder]= $code;
				
				// замяем совпавший код на его плейсхолдер
				$html = str_replace($code, $placeholder, $html);
				
			}
			else // не использвоать плейсхолдеры
			{
				$results[]= $code;
				$html = str_replace($code, '', $html);
			}
		}
		
		return $results;
	}
	
	
	// транслитерация строк с русскими буквами
	static function translit($str)
	{
		static $table = array(
			'а'=>'a',  'б'=>'b', 'в'=>'v', 'г'=>'g', 'д'=>'d', 'е'=>'e', 'ё'=>'yo', 
			'ж'=>'zh', 'з'=>'z', 'и'=>'i', 'й'=>'y', 'к'=>'k', 'л'=>'l', 'м'=>'m', 
			'н'=>'n',  'о'=>'o', 'п'=>'p', 'р'=>'r', 'с'=>'s', 'т'=>'t', 'у'=>'u', 
			'ф'=>'f',  'х'=>"h", 'ц'=>"ts",'ч'=>"ch",'ш'=>"sh",'щ'=>"shch", 
			'ъ'=>'',   'ь'=>'',	 'ы'=>'i', 'э'=>'e', 'ю'=>"yu", 'я'=>"ya",
			 
			'А'=>'A', 'Б'=>'B', 'В'=>'V', 'Г'=>'G', 'Д'=>'D', 'Е'=>'E', 'Ё'=>"YO",
			'Ж'=>'G', 'З'=>'Z', 'И'=>'I', 'Й'=>'Y', 'К'=>'K', 'Л'=>'L', 'М'=>'M', 
			'Н'=>'N', 'О'=>'O', 'П'=>'P', 'Р'=>'R', 'С'=>'S', 'Т'=>'T', 'У'=>'U', 
			'Ф'=>'F', 'Х'=>"H", 'Ц'=>"TS", 'Ч'=>"CH", 'Ш'=>"SH", 'Щ'=>"SHCH", 
			'Ъ'=>"",  'Ь'=>"",  'Ы'=>'I',  'Э'=>'E',  'Ю'=>"YU", 'Я'=>"YA"
		);

		//return strtr($str, $table);
		return str_replace(array_keys($table), array_values($table), $str);
	}

	
	// urlword($str)
	// подгатавливает строку для использования в качестве секции URL-пути
	// фильтрует $str от ненужных символов
	// допустимые символы:  a-z A-Z 0-9 ~-[]_
	// русские буквы транслитерируются в латинские
	static function  urlword($str) 
	{
		// pr($str);
		$str = strip_tags($str);
		$str = strtolower( trim( Filter::translit($str)));
		$str = str_replace( array('"', "'"), '', $str );
		// pr($str);
		
		$str = preg_replace(
					array('/[^a-zA-Z0-9\~\-\[\]_]+/',  '/[_-]+/'),
					'_', 
					$str); 
		
		$str = rtrim($str,'_');			
					
		return $str;
	}
	

	static function varname($str)
	{
		return $str;
	}

	static function dirname($str)
	{
		$str= trim($str, '/');
		return $str;
	}
	
	static function url($str)
	{
		return $str;
	}
	
	
	// Using this for SEO urls. I had to modify it a bit to get through the word wrap.  Pretty sure you can one line it a lot of it.
	static function encodeUrlParam ( $string )
	{
	  $string = trim($string);
		
	  if ( ctype_digit($string) )
	  {
		return $string;
	  }
	  else 
	  {      
		// replace accented chars
		$accents = '/&([A-Za-z]{1,2})(grave|acute|circ|cedil|uml|lig);/';
		$string_encoded = htmlentities($string,ENT_NOQUOTES,'UTF-8');

		$string = preg_replace($accents,'$1',$string_encoded);
		  
		// clean out the rest
		$replace = array('([\40])','([^a-zA-Z0-9-])','(-{2,})');
		$with = array('-','','-');
		$string = preg_replace($replace,$with,$string); 
	  } 

	  return strtolower($string);
	}

	
	
	static function filepath($str)
	{
		return $str;
	}
	
	// заменяет в строке $str $replaces keys на $replaces values
	static function replace($str, $replaces, $is_regexp=false)
	{
		list($search, $replace) = 
			array(array_keys($replaces), array_values($replaces));
			
		$str = $is_regexp 	? preg_replace($search, $replace, $str) 
							: str_replace($search, $replace, $str) ;
		
		return $str;						
	}
	
	
	
	

	static function str2regex($str)
	/*
	`Escape a string to be used as a regular expression pattern
	`Example: 	str2regex('http://www.example.com/s?q=php.net+docs')
				returns 'http:\/\/www\.example\.com\/s\?q=php\.net\+docs'
	*/
	{
        //All regex special chars (according to arkani at iol dot pt below):
        // \ ^ . $ | ( ) [ ]  * + ? { } ,
        
        $patterns = array('/\//', '/\^/', '/\./', '/\$/', '/\|/',
							'/\(/', '/\)/', '/\[/', '/\]/', '/\*/', '/\+/', 
							'/\?/', '/\{/', '/\}/', '/\,/');
        $replace = array('\/', '\^', '\.', '\$', '\|', '\(', '\)', 
							'\[', '\]', '\*', '\+', '\?', '\{', '\}', '\,');
        return preg_replace($patterns,$replace, $str);
	}

/* RegExp Help

The following chars in RegExp should be escaped if you are trying to match that character
\ ^ . $ | ( ) [ ]  * + ? { } ,

Special Character Definitions
\ Quote the next metacharacter
^ Match the beginning of the line
. Match any character (except newline)
$ Match the end of the line (or before newline at the end)
| Alternation
() Grouping
[] Character class
* Match 0 or more times
+ Match 1 or more times
? Match 1 or 0 times
{n} Match exactly n times
{n,} Match at least n times
{n,m} Match at least n but not more than m times
More Special Character Stuff
\t tab (HT, TAB)
\n newline (LF, NL)
\r return (CR)
\f form feed (FF)
\a alarm (bell) (BEL)
\e escape (think troff) (ESC)
\033 octal char (think of a PDP-11)
\x1B hex char
\c[ control char
\l lowercase next char (think vi)
\u uppercase next char (think vi)
\L lowercase till \E (think vi)
\U uppercase till \E (think vi)
\E end case modification (think vi)
\Q quote (disable) pattern metacharacters till \E
Even More Special Characters
\w Match a "word" character (alphanumeric plus "_")
\W Match a non-word character
\s Match a whitespace character
\S Match a non-whitespace character
\d Match a digit character
\D Match a non-digit character
\b Match a word boundary
\B Match a non-(word boundary)
\A Match only at beginning of string
\Z Match only at end of string, or before newline at the end
\z Match only at end of string
\G Match only where previous m//g left off (works only with /g) 

*/
   	
	/*
	$result = preg_replace('#{(?!disable1|disable2)[a-z0-9]+}#is', '$1', $foo);
	
	This code matches on all strings that do NOT start with "disable1" or "disable2" and contain of a-z0-9. It took me several hours to figuere out this very easy example!

	*/
	
	/*
Take care when you try to strip whitespaces out of an UTF-8 text. Using something like:

<?php
$text = preg_replace( "{\s+}", ' ', $text );
?>

brokes in my case the letter a which is hex c3a0. But a0 is a whitespace. So use 

<?php
$text = preg_replace( "{[ \t]+}", ' ', $text );
?>

to strip all spaces and tabs, or better, use a multibyte function like mb_ereg_replace. 
	*/
	
	/* 	TODO:::
	 The above example useful for filtering input data, then saving into mysql database, it's not need tobe decoded again, just use UTF-8 as charset.
	Please Note escaping special chars between delimiter.. 
	 */
	static function str4db($str)
	{
		$converted    = 
			array(
			//3 of special chars

			'/(;)/ie', 
			'/(#)/ie', 
			'/(&)/ie', 

			//MySQL reserved words!
			//Check mysql website!
			'/(ACTION)/ie', '/(ADD)/ie', '/(ALL)/ie', '/(ALTER)/ie', '/(ANALYZE)/ie', '/(AND)/ie', '/(AS)/ie', '/(ASC)/ie',

			//remaining of special chars
			'/(<)/ie', '/(>)/ie', '/(\.)/ie', '/(,)/ie', '/(\?)/ie', '/(`)/ie', '/(!)/ie', '/(@)/ie', '/(\$)/ie', '/(%)/ie', '/(\^)/ie', '/(\*)/ie', '/(\()/ie', '/(\))/ie', '/(_)/ie', '/(-)/ie', '/(\+)/ie', 
			'/(=)/ie', '/(\/)/ie', '/(\|)/ie', '/(\\\)/ie', "/(')/ie", '/(")/ie', '/(:)/'
			);

		$input_text = preg_replace($converted, "UTF_to_Unicode('\\1')", $text);
	}
	static function UTF_to_Unicode($data){

	//return $data;
	}
	
	
	
	static function bbcode($str)
	{
		$bbcode = array(
			"/\[b\](.*?)\[\/b\]/is" 		 => "<strong>$1</strong>",
			"/\[u\](.*?)\[\/u\]/is" 		 => "<u>$1</u>",
			"/\[url\=(.*?)\](.*?)\[\/b\]/is" => "<a href='$1'>$2</a>",
		);
		
		$str = preg_replace(array_keys($bbcode), array_values($bbcode), $str);
		return $str;
	}
	static function AddBB($var) { 
        $search = array( 
                '/\[b\](.*?)\[\/b\]/is', 
                '/\[i\](.*?)\[\/i\]/is', 
                '/\[u\](.*?)\[\/u\]/is', 
                '/\[img\](.*?)\[\/img\]/is', 
                '/\[url\](.*?)\[\/url\]/is', 
                '/\[url\=(.*?)\](.*?)\[\/url\]/is' 
                ); 

        $replace = array( 
                '<strong>$1</strong>', 
                '<em>$1</em>', 
                '<u>$1</u>', 
                '<img src="$1" />', 
                '<a href="$1">$1</a>', 
                '<a href="$1">$2</a>' 
                ); 

        $var = preg_replace ($search, $replace, $var); 
        return $var; 
} 


/*
This function takes a URL and returns a plain-text version of the page. It uses cURL to retrieve the page and a combination of regular expressions to strip all unwanted whitespace. This function will even strip the text from STYLE and SCRIPT tags, which are ignored by PHP functions such as strip_tags (they strip only the tags, leaving the text in the middle intact). 

Regular expressions were split in 2 stages, to avoid deleting single carriage returns (also matched by \s) but still delete all blank lines and multiple linefeeds or spaces, trimming operations took place in 2 stages. 
*/
static function webpage2txt($url) 
{ 
	$user_agent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"; 

	$ch = curl_init();    // initialize curl handle 
	curl_setopt($ch, CURLOPT_URL, $url); // set url to post to 
	curl_setopt($ch, CURLOPT_FAILONERROR, 1);              // Fail on errors 
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);    // allow redirects 
	curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); // return into a variable 
	curl_setopt($ch, CURLOPT_PORT, 80);            //Set the port number 
	curl_setopt($ch, CURLOPT_TIMEOUT, 15); // times out after 15s 

	curl_setopt($ch, CURLOPT_USERAGENT, $user_agent); 

	$document = curl_exec($ch); 

	$search = array('@<script[^>]*?>.*?</script>@si',  // Strip out javascript 
	'@<style[^>]*?>.*?</style>@siU',    // Strip style tags properly 
	'@<[\/\!]*?[^<>]*?>@si',            // Strip out HTML tags 
	'@<![\s\S]*?–[ \t\n\r]*>@',         // Strip multi-line comments including CDATA 
	'/\s{2,}/', 

	); 

	$text = preg_replace($search, "\n", html_entity_decode($document)); 

	$pat[0] = "/^\s+/"; 
	$pat[2] = "/\s+\$/"; 
	$rep[0] = ""; 
	$rep[2] = " "; 

	$text = preg_replace($pat, $rep, trim($text)); 

	return $text; 
} 

	
	

}